package com.gavin;

import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.gavin.plugin.database.IAtom;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.gavin.model.Request;
import com.gavin.model.Response;
import com.gavin.model.Result;
import com.gavin.plugin.service.impl.TransBus;
import com.gavin.utils.IOUtils;
import com.gavin.utils.Injector;
import com.gavin.utils.Resources;

/**
 * <pre>
 * 数据库操作插件
 * ---------------------- ----------------------
 *  默认配置文件名为：config.properties
 *  
 * 配置项
 * ---------------------- ----------------------
 *  0.配置文件加载方式
 *  dbbus.loadType
 * 
 *  1.  数据库总线配置文件名 ，默认为：dbbus_%s.xml
 *  dbbus.fileName
 * 
 *  2. 数据库总线配置项目名称
 *  dbbus.projectName
 * 
 *  3.数据库总线配置模式，分别代表 开发环境，测试环境，生产环境： dev | test | pro
 *  dbbus.env 
 * </pre>
 * @author wdm  @date 2018年1月10日
 * @version 1.0
 */
@SuppressWarnings("unchecked")
public class DBTrans {
	private static Logger logger = LoggerFactory.getLogger(DBTrans.class);

	private static final String GAVIN_VERSION="2.05";

	private Properties properties;
	
	//配置信息 dbtrans.dbbusFileName=dbbus_%s.xml, dbtrans.dbbusMode=test
//	public static final String LOAD_TYPE="dbtrans.loadType";////配置文件加载方式 classpath   filepath   改进以/开头的是filepath
	public static final String DBBUS_FILE="dbtrans.dbbusFileName";//dbbusFileName
	public static final String DBBUS_ENV="dbtrans.dbbusMode";
	public static final String PROJECT_NAME="dbtrans.projectName";
	public static final String DEFAULT_PAGENUMBER="dbtrans.pageNumber";
//	public static final String LOAD_TYPE="dbbus.loadType";////配置文件加载方式 classpath   filepath
//	public static final String DBBUS_FILE="dbbus.fileName";
//	public static final String DBBUS_ENV="dbbus.env";
//	public static final String PROJECT_NAME="dbbus.projectName";
	
	//默认值
	private static String defaultTransBusFileName="dbbus_%s.xml";
//	private static String defaultConfigFileName="config.properties";
	private static String defaultProjectName="app";
	public static boolean isRuning=false;
	public static long defaultPageNumber=1L;


	
	private DBTrans() {
		properties=new Properties();
	}
	
	public static class DBTransIntance{
		private static DBTrans instance = new DBTrans();
	}
	
	public static DBTrans getInstance() {
		return DBTransIntance.instance;
	}
	
	public DBTrans config(Properties properties) {
		if(properties!=null){
			this.properties=properties;
		}
		return DBTransIntance.instance;
	}

	
	/**
	 * 事务总线对象
	 */
	private TransBus dbbus;

	public boolean isRunning() {
		return this.dbbus.isRunning();
	}

	// 启动
	public boolean start() {
//		if(this.properties.size()==0){
//			Properties properties = loadConfigFromResource(defaultConfigFileName, "utf-8", DBTrans.class.getClassLoader());
//			if (properties==null) {
//				logger.error("load config file failed : "+defaultConfigFileName);
//				logger.error("please check config is exist!!!  Config Item :{} & {} & {}", DBBUS_ENV, PROJECT_NAME,DBBUS_FILE);
//				return false;
//			}
//			this.properties=properties;
//			logger.info("load config file success!!!");
//		}

		defaultTransBusFileName=properties.getProperty(DBBUS_FILE,defaultTransBusFileName);
		defaultProjectName=properties.getProperty(PROJECT_NAME,defaultProjectName);
		defaultPageNumber=Long.valueOf(properties.getProperty(DEFAULT_PAGENUMBER,"1"));
		String env=properties.getProperty(DBBUS_ENV,"pro");
//		String loadType=properties.getProperty(LOAD_TYPE, "classpath");

		logger.info("--------------------------------------------------------------------------------------");
		logger.info("{} & {} & {}",PROJECT_NAME,DBBUS_ENV, DBBUS_FILE);
		logger.info("{} >>> {} >>> {}",defaultProjectName, env , defaultTransBusFileName);
		logger.info("--------------------------------------------------------------------------------------");
		
		// 初始化数据总线
		this.dbbus = new TransBus();
		String filePath=String.format(defaultTransBusFileName, env);
		String strDbBusXML = "";
		if(!filePath.startsWith("/")){
			strDbBusXML=IOUtils.readTextFile(filePath, "utf-8");
		}else{
			strDbBusXML=IOUtils.readTextResource(filePath, "utf-8", null);
		}

		Result ret = this.dbbus.init(strDbBusXML, null);
		if (ret==null || ret.getCode() != 0) {
			logger.info("gavin version = "+GAVIN_VERSION);
			logger.error(defaultProjectName+" dbbus init failed: " + ret.getText());

			if(strDbBusXML==null){
				logger.error(filePath+" is null !!!");
				System.exit(0);
				return false;
			}
			try {
				//替换密码
				Pattern pattern = Pattern.compile("Password.*=.*\".*\"");
				Matcher matcher = pattern.matcher(strDbBusXML);
				logger.error(matcher.replaceAll("Password=\"******\""));
			} finally {
				System.exit(0);
			}
			return false;
		}

		// 启动数据总线
		ret = this.dbbus.start();
		if (ret==null || ret.getCode() != 0) {
			dbbus.destroy();
			logger.error(defaultProjectName+" dbbus start failed: " + ret.getText());
			System.exit(0);
			return false;
		}

		logger.info("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
		logger.info("VERSION: "+GAVIN_VERSION);
		logger.info(defaultProjectName+"'s dbbus start success!!!");
		logger.info("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
		return true;
	}

	public void stop() {
		if (this.dbbus.isRunning()) {
			this.dbbus.stop();
			this.dbbus.destroy();
		}
	}


	//trans-------------------------------------------------------------------------------------------------------------
	/**
	 * 执行事务
	 * @param request
	 * @return Response
	 */
	public static Response execute(Request request) {
		logger.info("DBTrans execution : "+request.getServiceName()+"."+request.getTransName());
		Response response=Response.ifNull( DBTrans.getInstance().dbbus.execute(request)).log();
		return response;
	}

	/**
	 * @title  执行原子事务
	 * @author Yudao 王冬明（woyuwodao@gmail.com） @date 2018/11/7 18:06
	 * @param
	 * @return
	 */
	public static Response tx(IAtom iAtom){
        logger.info("DBTrans execution : "+iAtom.getRequest().getServiceName()+"."+iAtom.getRequest().getTransName());
        Response response=Response.ifNull( DBTrans.getInstance().dbbus.execute(iAtom)).log();
        return response;
	}

	/**
	 * 查询list集合
	 * 如果查询失败或异常则返回null否则返回空集合
	 * @param request
	 * @param clazz
	 * @return
	 */
	public static <M> M list(Request request,Class<?> clazz) {
		logger.info("DBTrans execution : "+request.getServiceName()+"."+request.getTransName());
		Response response=Response.ifNull(DBTrans.getInstance().dbbus.execute(request)).log();
		if(response.fail()){
			logger.error("DBTrans response error:"+response);
			return null;
		}
		return (M) Injector.injectList(clazz, response, true);
	}
	
	/**
	 * 查詢一條數據
	 * 如果查询失败或查询异常，throw new RuntimeException("查询失败")
	 * @param request
	 * @param clazz
	 * @return
	 */
	public static <M> M bean(Request request,Class<?> clazz) {
		logger.info("DBTrans execution : "+request.getServiceName()+"."+request.getTransName());
		Response response=Response.ifNull(DBTrans.getInstance().dbbus.execute(request)).log();
		if(response.fail()){
			logger.error("DBTrans response error:"+response);
			throw new RuntimeException("查询失败");
//			return null;
		}
		return (M) Injector.injectBean(clazz, response, true);
	}
	
	/**
	 * 查詢一條數據并直接返回Response结果
	 * @param request
	 * @param clazz
	 * @return
	 */
	public static Response beanResult(Request request,Class<?> clazz) {
		logger.info("DBTrans execution : "+request.getServiceName()+"."+request.getTransName());
		Response response=Response.ifNull(DBTrans.getInstance().dbbus.execute(request)).log();
		if(response.fail()){
			logger.error("DBTrans response error:"+response);
			return response;
		}
		Object obj=Injector.injectBean(clazz, response, true);
		response.setData(obj);
		return response;
	}
	
	/**
	 * use beanResult(request,clazz)
	 * @param request
	 * @param clazz
	 * @return
	 */
	@Deprecated
	public static Response result(Request request,Class<?> clazz) {
		return beanResult(request,clazz);
	}
	
	/**
	 * 查詢分頁
	 * 查询失败或异常时返回null
	 * @param request
	 * @param clazz
	 * @return
	 */
	public static <M> M page(Request request,Class<?> clazz) {
		logger.info("DBTrans execution : "+request.getServiceName()+"."+request.getTransName());
		Response response=Response.ifNull(DBTrans.getInstance().dbbus.execute(request)).log();
		if(response.fail()){
			logger.error("DBTrans response error:"+response);
			return null;
		}
		if(request.model().exists("pageSize"))response.set("pageSize", request.model().getInteger("pageSize"));
		if(request.model().exists("pageNumber"))response.set("pageNumber", request.model().getInteger("pageNumber"));
		return (M) Injector.injectPage(clazz, response, true);
	}
}


